home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
fmt200.zip
/
FMT.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-02-07
|
112KB
|
3,983 lines
;***********************************************************************
;* *
;* Fmt.asm 07-FEB-1993 *
;* *
;* Format Floppy Disk - version 2.00 - MS-DOS 5.0 style format *
;* *
;* Designed for use with IBM AT compatible sytems (including PS/2s) *
;* *
;***********************************************************************
;* *
;* Developed under MS-DOS version 5.00 *
;* *
;* Compiled with Borland Turbo Assembler version 3.1 *
;* *
;* Linked with Borland Turbo Link version 5.22b *
;* *
;***********************************************************************
;* *
;* Syntax: FMT d: size [V] [S] [D] [N|R] [U] [C] *
;* *
;* where: d = drive (A or B), size = floppy size in Kb, *
;* *
;* the optional V enables format verification, the optional S *
;* *
;* copies the system files, the optional D enables the enhanced *
;* *
;* DOS compatibility mode, the optional N bypasses the prompt, *
;* *
;* the optional R enables recursive formatting with prompting, *
;* *
;* the optional C enables the 720K 1 sector per cluster option, *
;* *
;* and the optional U creates a UNIX disk (F6h fills entire disk) *
;* *
;* supported sizes are: *
;* *
;* 360 for a 360 Kb floppy in a 360 Kb or 1.2 Mb drive *
;* 720 for a 720 Kb floppy in a 720 Kb, 1.44 Mb, or 2.88 Mb drive *
;* 1200 for a 1.2 Mb floppy in a 1.2 Mb drive *
;* 1440 for a 1.44 Mb floppy in a 1.44 Mb or 2.88 Mb drive *
;* 2880 for a 2.88 Mb floppy in a 2.88 Mb drive *
;* *
;***********************************************************************
;* *
;* Exit codes: *
;* *
;* 0 = successful format *
;* 1 = failure during format, verify, or write *
;* 2 = disk size / drive type combination is not supported *
;* 3 = requested drive does not exist *
;* 4 = invalid or null command line *
;* 5 = system files not found or error writing system files *
;* 6 = computer is not AT compatible *
;* 7 = insufficient memory for file copy buffer (system transfer) *
;* 8 = insufficient stack space for program *
;* 9 = program aborted by user (Control-C, Break, or Escape) *
;* 10 = unknown drive type (CMOS says floppy type is greater than 5) *
;* 11 = memory allocation error (while attempting to reduce memory) *
;* 12 = both N and R options specified (only one allowed) *
;* 13 = 720K option secified, but not 720K format *
;* *
;***********************************************************************
;* *
;* In order to use the system transfer option, the following files *
;* *
;* must be present in the root diectory of the default drive: *
;* *
;* 1: IBMBIO.COM or IO.SYS (normally a hidden file) *
;* *
;* 2: IBMDOS.COM or MSDOS.SYS (normally a hidden file) *
;* *
;* 3: COMMAND.COM *
;* *
;***********************************************************************
;* *
;* Compile with Borland Turbo Assembler(R) version 1.0 or greater *
;* *
;* tasm /t fmt tasm /t /zi fmt *
;* or *
;* tlink /t /x fmt tlink /v /x fmt *
;* *
;* tdstrip -c -s fmt *
;* *
;* for use with Turbo Debugger(R) *
;* or *
;* *
;* Compile with Microsoft(R) Macro Assembler version 5.0 or greater *
;* *
;* masm /t fmt; *
;* *
;* link fmt; *
;* *
;* exe2bin fmt fmt.com *
;* *
;* del fmt.exe *
;* *
;***********************************************************************
;* *
;* Written by: *
;* *
;* Clair Alan Hardesty *
;* Design Validation Engineer II *
;* Silicon Systems, Inc. *
;* 138 New Mohawk Road *
;* Nevada City, CA 95959-3262 *
;* *
;* TEL : (916) 478-8201 *
;* FAX : (916) 478-8251 *
;* *
;***********************************************************************
;* *
;* Microsoft(R) is a registered trademark of Microsoft Corporation *
;* *
;* IBM(R) and PS/2 are registered trademarks of International *
;* *
;* Business Machines Corporation *
;* *
;* Turbo Assembler(R) and Turbo Debugger(R) are registered trademarks *
;* *
;* of Borland International *
;* *
;***********************************************************************
;* *
;* Revision history: *
;* *
;* Version 1.00 : 23-JAN-1990 *
;* *
;* Initial public release *
;* *
;* Version 1.10 : 03-FEB-1990 *
;* *
;* Fixed MASM bugs *
;* *
;* Added MASM version 5.0 compatibility *
;* *
;* Improved compatibility for drive type determination *
;* *
;* Added a break handler and `user abort' message *
;* *
;* Added some new exit codes *
;* *
;* Improved the boot record code *
;* *
;* Version 1.20 : 10-JUL-1990 *
;* *
;* Fixed serial number generation to match IBM format exactly *
;* *
;* Fixed system file transfer to work with IBM or Microsoft DOS *
;* *
;* Modified the user abort code to accept the ESCAPE, CONTROL-C, *
;* *
;* or BREAK keys, and fixed some bugs in the user abort code *
;* *
;* Added recursive formatting capability *
;* *
;* Version 1.30 : 22-DEC-1990 *
;* *
;* Comment clarifications *
;* *
;* Minor code improvements *
;* *
;* Version 1.40 : 21-JUN-1991 *
;* *
;* Improved compatibility for some machines (mainly PS/2s) *
;* *
;* Version 1.50 : 28-FEB-1992 *
;* *
;* Upgraded to MS-DOS 5.0 with support for 2.88 Mb floppy drives *
;* *
;* Fixed a bug in the reset subroutine retry code *
;* *
;* Version 1.60 : 09-MAR-1992 *
;* *
;* Fixed a bug in the format subroutine that caused some machines *
;* (COMPAQs) to fail verification. Thanks to Ralph Riggs for *
;* pointing out this bug and assisting in it's eradication. *
;* *
;* Version 1.70 : 01-NOV-1992 *
;* *
;* Fixed a bug in the stack check code. *
;* Added the UNIX format option. *
;* Removed the copyright - released to the public domain *
;* *
;* Version 2.00 : 07-FEB-1993 *
;* *
;* added 720 Kb floppy 1 sector per cluster option *
;* *
;***********************************************************************
;***********************************************************************
; program equates
;***********************************************************************
TRUE equ 01h
FALSE equ 00h
ESC_KEY equ 011bh
CTRL_C_KEY equ 2e03h
NULL equ 00h
BACKSPACE equ 08h
TAB equ 09h
LF equ 0ah
CR equ 0dh
SPACE equ 20h
BOOT equ 7c00h ; boot loader base address
;***********************************************************************
; set-up for interrupt vector table access
;***********************************************************************
seg_zero segment at 0000h
assume es:seg_zero
org 0000h
seg_zero ends
;***********************************************************************
; set-up for the far jump used in the boot record code
;***********************************************************************
ibmbio segment at 0070h
assume cs:ibmbio
org 0000h
program_loader label far
ibmbio ends
;***********************************************************************
; set-up for system identification
;***********************************************************************
rom_bios segment at 0ffffh
assume ds:rom_bios
org 000eh
system_id label byte
rom_bios ends
;***********************************************************************
; main program code
;***********************************************************************
cseg segment
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
org 0100h
entry_point:
jmp start ; skip over data area
;***********************************************************************
; format data area
;***********************************************************************
BCD_size: db 4 dup (?) ; disk size in BCD
binary_size: dw ? ; disk size in binary
verify: db FALSE ; default is no verification
system: db FALSE ; default is no system file transfer
prompt: db TRUE ; default is prompt to insert floppy
recurse: db FALSE ; default is no recursion
prmt_or_rcrs: db FALSE ; used to allow only one of the options
standard: db FALSE ; use DOS standard format parameters
cluster_720K: db FALSE ; default is 2 sectors per cluster
drive_number: db ?
disk_drive: dw ?
max_track: db ?
retry_count: db ?
write_track: dw ?
write_head: db ?
write_sector: db ?
cursor: dw ?
stack_size: dw 1024 ; minimum allowable stack space
minimum_buffer: dw 4096 ; minimum file copy buffer size
buffer_size: dw ? ; actual file copy buffer size
system_exists: db ? ; boolean for system on default drive
is_ibm: db ? ; boolean for PC-DOS or MS-DOS
unix: db ? ; boolean for UNIX format
; the reset subroutine needs a dedicated retry count
reset_retry_count: db ?
;***********************************************************************
disk_size: db ?
; 1 = 360kb
; 2 = 1.2Mb
; 3 = 720kb
; 4 = 1.44Mb
; 5 = 2.88Mb
drive_type: db ?
; 0 = no drive
; 1 = 360kb
; 2 = 1.2Mb
; 3 = 720kb
; 4 = 1.44Mb
; 5 = 2.88Mb
;***********************************************************************
stack_pointer:
dw ? ; storage for initial stack pointer (eases some exits)
parameter_pointer:
dd ? ; storage for the original disk parameter table pointer
control_break:
dd ? ; storage for the original control-break handler vector
;***********************************************************************
floppy_table:
; 360 Kb
db 0FDh ; media descriptor
db 40 ; number of tracks
dw 9 ; sectors per track
dw 112 ; entries per root directory
db 7 ; sectors per root directory
db 2 ; sectors per cluster
dw 2 ; sectors per FAT
; 1.2 Mb
db 0F9h ; media descriptor
db 80 ; number of tracks
dw 15 ; sectors per track
dw 224 ; entries per root directory
db 14 ; sectors per root directory
db 1 ; sectors per cluster
dw 7 ; sectors per FAT
; 720 Kb - 2 sectors per cluster
db 0F9h ; media descriptor
db 80 ; number of tracks
dw 9 ; sectors per track
dw 112 ; entries per root directory
db 7 ; sectors per root directory
db 2 ; sectors per cluster
dw 3 ; sectors per FAT
; 1.44 Mb
db 0F0h ; media descriptor
db 80 ; number of tracks
dw 18 ; sectors per track
dw 224 ; entries per root directory
db 14 ; sectors per root directory
db 1 ; sectors per cluster
dw 9 ; sectors per FAT
; 2.88 Mb
db 0F0h ; media descriptor
db 80 ; number of tracks
dw 36 ; sectors per track
dw 240 ; entries per root directory
db 15 ; sectors per root directory
db 2 ; sectors per cluster
dw 9 ; sectors per FAT
; 720 Kb - 1 sector per cluster
db 0F9h ; media descriptor
db 80 ; number of tracks
dw 9 ; sectors per track
dw 112 ; entries per root directory
db 7 ; sectors per root directory
db 1 ; sectors per cluster
dw 5 ; sectors per FAT
;***********************************************************************
parameter_table: ; enables fast formatting
; uses some non-standard parameters for improved speed
; 360 Kb
db 0D2h,002h,009h,002h,009h,02Ah,0FFh,050h,0F6h,001h,001h
; 1.2 Mb
db 082h,002h,009h,002h,00Fh,01Bh,0FFh,054h,0F6h,001h,001h
; 720 Kb
db 012h,002h,009h,002h,009h,02Ah,0FFh,050h,0F6h,001h,001h
; 1.44 Mb
db 012h,002h,009h,002h,012h,01Bh,0FFh,06Ch,0F6h,001h,001h
; 2.88 Mb
db 012h,002h,009h,002h,024h,01Bh,0FFh,06Ch,0F6h,001h,001h
standard_parameter_table: ; uses DOS standards for compatibility
; uses DOS standard parameters for compatibility (slower)
; 360 Kb
db 0DFh,002h,025h,002h,009h,02Ah,0FFh,050h,0F6h,00Fh,008h
; 1.2 Mb
db 0DFh,002h,025h,002h,00Fh,01Bh,0FFh,054h,0F6h,00Fh,008h
; 720 Kb
db 0DFh,002h,025h,002h,009h,02Ah,0FFh,050h,0F6h,00Fh,008h
; 1.44 Mb
db 0AFh,002h,025h,002h,012h,01Bh,0FFh,06Ch,0F6h,00Fh,008h
; 2.88 Mb
db 0DFh,002h,025h,002h,024h,01Bh,0FFh,06Ch,0F6h,00Fh,008h
;***********************************************************************
; format sector tables
;***********************************************************************
sector_table_0:
db 000h,000h,001h,002h
db 000h,000h,002h,002h
db 000h,000h,003h,002h
db 000h,000h,004h,002h
db 000h,000h,005h,002h
db 000h,000h,006h,002h
db 000h,000h,007h,002h
db 000h,000h,008h,002h
db 000h,000h,009h,002h
db 000h,000h,00Ah,002h
db 000h,000h,00Bh,002h
db 000h,000h,00Ch,002h
db 000h,000h,00Dh,002h
db 000h,000h,00Eh,002h
db 000h,000h,00Fh,002h
db 000h,000h,010h,002h
db 000h,000h,011h,002h
db 000h,000h,012h,002h
db 000h,000h,013h,002h
db 000h,000h,014h,002h
db 000h,000h,015h,002h
db 000h,000h,016h,002h
db 000h,000h,017h,002h
db 000h,000h,018h,002h
db 000h,000h,019h,002h
db 000h,000h,01Ah,002h
db 000h,000h,01Bh,002h
db 000h,000h,01Ch,002h
db 000h,000h,01Dh,002h
db 000h,000h,01Eh,002h
db 000h,000h,01Fh,002h
db 000h,000h,020h,002h
db 000h,000h,021h,002h
db 000h,000h,022h,002h
db 000h,000h,023h,002h
db 000h,000h,024h,002h
sector_table_1:
db 000h,001h,001h,002h
db 000h,001h,002h,002h
db 000h,001h,003h,002h
db 000h,001h,004h,002h
db 000h,001h,005h,002h
db 000h,001h,006h,002h
db 000h,001h,007h,002h
db 000h,001h,008h,002h
db 000h,001h,009h,002h
db 000h,001h,00Ah,002h
db 000h,001h,00Bh,002h
db 000h,001h,00Ch,002h
db 000h,001h,00Dh,002h
db 000h,001h,00Eh,002h
db 000h,001h,00Fh,002h
db 000h,001h,010h,002h
db 000h,001h,011h,002h
db 000h,001h,012h,002h
db 000h,001h,013h,002h
db 000h,001h,014h,002h
db 000h,001h,015h,002h
db 000h,001h,016h,002h
db 000h,001h,017h,002h
db 000h,001h,018h,002h
db 000h,001h,019h,002h
db 000h,001h,01Ah,002h
db 000h,001h,01Bh,002h
db 000h,001h,01Ch,002h
db 000h,001h,01Dh,002h
db 000h,001h,01Eh,002h
db 000h,001h,01Fh,002h
db 000h,001h,020h,002h
db 000h,001h,021h,002h
db 000h,001h,022h,002h
db 000h,001h,023h,002h
db 000h,001h,024h,002h
;***********************************************************************
; file copy data area
;***********************************************************************
ibm_bios_source_path:
db "d:\"
ibm_bios_source_filename:
db "IBMBIO.COM",NULL,BACKSPACE
db "$"
ibm_bios_destination_path:
db "d:\"
ibm_bios_destination_filename:
db "IBMBIO.COM",NULL,BACKSPACE
db "$"
ibm_dos_source_path:
db "d:\"
ibm_dos_source_filename:
db "IBMDOS.COM",NULL,BACKSPACE
db "$"
ibm_dos_destination_path:
db "d:\"
ibm_dos_destination_filename:
db "IBMDOS.COM",NULL,BACKSPACE
db "$"
ms_bios_source_path:
db "d:\"
ms_bios_source_filename:
db "IO.SYS",NULL,BACKSPACE
db "$"
ms_bios_destination_path:
db "d:\"
ms_bios_destination_filename:
db "IO.SYS",NULL,BACKSPACE
db "$"
ms_dos_source_path:
db "d:\"
ms_dos_source_filename:
db "MSDOS.SYS",NULL,BACKSPACE
db "$"
ms_dos_destination_path:
db "d:\"
ms_dos_destination_filename:
db "MSDOS.SYS",NULL,BACKSPACE
db "$"
cmd_source_path:
db "d:\"
cmd_source_filename:
db "COMMAND.COM",NULL,BACKSPACE
db "$"
cmd_destination_path:
db "d:\"
cmd_destination_filename:
db "COMMAND.COM",NULL,BACKSPACE
db "$"
ibm_bios_name:
db "IBMBIO COM"
ibm_dos_name:
db "IBMDOS COM"
ms_bios_name:
db "IO SYS"
ms_dos_name:
db "MSDOS SYS"
;***********************************************************************
; informational messages
;***********************************************************************
cr_lf:
db CR,LF
db "$"
insert_floppy:
db "Put desired floppy in drive "
insert_drive:
db ?
db ": and press any key"
db "$"
initializing:
db "Initializing"
db "$"
clear_line:
db 50 dup (BACKSPACE)
db 50 dup (SPACE)
db 50 dup (BACKSPACE)
db "$"
format_display:
db 26 dup (BACKSPACE)
db "Formatting track "
format_track_number:
db 2 dup (?)
db " head "
format_head_number:
db ?
db "$"
verify_display:
db 26 dup (BACKSPACE)
db "Verifying track "
verify_track_number:
db 2 dup (?)
db " head "
verify_head_number:
db ?
db "$"
boot_message:
db 26 dup (BACKSPACE)
db 26 dup (SPACE)
db 26 dup (BACKSPACE)
db "Writing boot record"
db "$"
fat_message:
db 19 dup (BACKSPACE)
db 19 dup (SPACE)
db 19 dup (BACKSPACE)
db "Writing FATs"
db "$"
dir_message:
db 12 dup (BACKSPACE)
db 12 dup (SPACE)
db 12 dup (BACKSPACE)
db "Writing root directory"
db "$"
file_copy_message:
db 22 dup (BACKSPACE)
db 22 dup (SPACE)
db 22 dup (BACKSPACE)
db "Copying system files"
db "$"
exit_message:
db 22 dup (BACKSPACE)
db 22 dup (SPACE)
db 22 dup (BACKSPACE)
db "Format complete"
db CR,LF
db "$"
;***********************************************************************
; error messages
;***********************************************************************
allocation_error:
db "Memory allocation error"
db CR,LF
db "$"
no_stack_space:
db "Not enough room for program stack"
db CR,LF
db "$"
computer_message:
db "IBM AT or compatible computer required"
db CR,LF
db "$"
no_drive_error:
db "No such drive in system"
db CR,LF
db "$"
reset_error:
db "Disk controller reset error"
db CR,LF
db "$"
set_drive_error:
db "Disk drive type not supported by BIOS"
db CR,LF
db "$"
get_type_error:
db "Unknown drive type"
db CR,LF
db "$"
no_floppy_error:
db "No floppy in drive"
db CR,LF
db "$"
set_disk_error:
db "Disk / Drive combination not supported"
db CR,LF
db "$"
write_boot_error:
db "Error writing boot record"
db CR,LF
db "$"
write_fat_error:
db "Error writing FAT"
db CR,LF
db "$"
write_dir_error:
db "Error writing directory"
db CR,LF
db "$"
write_protect_error:
db "Disk is write protected"
db CR,LF
db "$"
user_abort:
db "User abort"
db CR,LF
db "$"
error_during_format:
db "Error during format"
db CR,LF
db "$"
disk_type_error:
db "Defective floppy or wrong floppy type"
db CR,LF
db "$"
verify_error:
db "Verification error"
db CR,LF
db "$"
buffer_space_error:
db "No room for file copy buffer"
db CR,LF
db "$"
option_error:
db CR,LF
db "Both N and R options specified (only one allowed)"
db CR,LF
db "$"
cluster_720K_error:
db CR,LF
db "720K 1 sector option specified, but not 720K format"
db CR,LF
db "$"
help_message:
db CR,LF
db "FMT version 2.00 : 07-FEB-1993 : Written by Clair Alan Hardesty"
db CR,LF,LF
db " syntax: FMT d: size [V] [S] [D] [N|R] [U] [C]"
db CR,LF,LF
db " where: d = drive (A or B), size = floppy size in Kb,"
db CR,LF,LF
db " the optional V enables format verification, the optional S"
db CR,LF,LF
db " copies the system files, the optional D enables the enhanced"
db CR,LF,LF
db " DOS compatibility mode, the optional N bypasses the prompt,"
db CR,LF,LF
db " the optional R enables recursive formatting with prompting,"
db CR,LF,LF
db " the optional C enables the 720K 1 sector per cluster option,"
db CR,LF,LF
db " and the optional U creates a UNIX disk (F6h fills entire disk)"
db CR,LF,LF
db " supported sizes are:"
db CR,LF,LF
db " 360 for a 360 Kb floppy in a 360 Kb or 1.2 Mb drive"
db CR,LF
db " 720 for a 720 Kb floppy in a 720 Kb, 1.44 Mb, or 2.88 Mb drive"
db CR,LF
db " 1200 for a 1.2 Mb floppy in a 1.2 Mb drive"
db CR,LF
db " 1440 for a 1.44 Mb floppy in a 1.44 Mb or 2.88 Mb drive"
db CR,LF
db " 2880 for a 2.88 Mb floppy in a 2.88 Mb drive"
db CR,LF
db "$"
;***********************************************************************
; reduce memory allocation and check stack space
;***********************************************************************
start:
; if more than 64 Kb is available, then SP => FFFCh
cmp sp,0fffch
jl check_stack
; reduce memory allocation to 64 Kb
mov bx,1000h
mov ah,4ah
int 21h
jnc check_stack
; set exit code to 11 (memory allocation error)
mov dx,offset allocation_error
mov ah,09h
int 21h
mov ax,4c0bh
int 21h
check_stack:
; check stack space
mov ax,sp
mov bx,offset file_buffer
sub ax,bx
cmp ax,word ptr [stack_size]
ja room_for_stack
; set exit code to 9 (not enough room for stack)
mov dx,offset no_stack_space
mov ah,09h
int 21h
mov ax,4c08h
int 21h
room_for_stack:
; save the stack pointer
mov word ptr [stack_pointer],sp
;***********************************************************************
; check cpu and computer type
;***********************************************************************
; check CPU for 80286 or above
push ds
xor ax,ax
push ax
popf
pushf
pop ax
and ax,8000h
cmp ax,8000h
je short not_an_at
; check the model byte in ROM
mov ax,rom_bios
mov ds,ax
assume ds:rom_bios
cmp system_id,0fch ; AT or compatible
je at_or_better
cmp system_id,0fah ; most 80286 P/S-2 models
je at_or_better
cmp system_id,0f8h ; P/S-2 model 80
je at_or_better
; additional model identification code goes here
not_an_at:
; computer is not AT compatible
pop ds
assume ds:cseg
mov dx,offset computer_message
mov ah,09h
int 21h
; set exit code to 6 (not an AT or compatible)
mov sp,word ptr [stack_pointer]
mov ax,4c06h
int 21h
at_or_better:
;***********************************************************************
cseg ends
.286 ; enable the 80286 instruction set
cseg segment
;***********************************************************************
pop ds
assume ds:cseg
; initialize some variables
mov cl,0 ; parameter counter
mov dl,0 ; disk size digit counter
mov di,offset BCD_size ; temporary disk size storage
mov bx,0080h ; pointer to the command line
;***********************************************************************
; parse the command line
;***********************************************************************
parse_loop:
inc bx
cmp byte ptr [bx],CR
jne not_finished
jmp got_command
not_finished:
cmp byte ptr [bx],SPACE
je parse_loop
cmp byte ptr [bx],TAB
je parse_loop
cmp cl,0
jg number_check
and byte ptr [bx],5fh ; capitalize drive letter
; check the drive letter (must be drive A: or B:)
cmp byte ptr [bx],'A'
jnl check_for_b
jmp help ; invalid drive
check_for_b:
cmp byte ptr [bx],'B'
jng store_drive
jmp help ; invalid drive
store_drive:
mov al,byte ptr [bx]
sub al,'A'
mov byte ptr [drive_number],al
colon_check:
cmp byte ptr [bx+1],':'
je found_colon
jmp help ; no colon after drive letter
found_colon:
inc bx ; skip over the colon
inc cl ; increment parameter count
jmp parse_loop
number_check:
cmp cl,1
jg check_option
cmp byte ptr [bx],'0'
jnl maybe_a_number
jmp help ; not a number
maybe_a_number:
cmp byte ptr [bx],'9'
jng is_a_number
jmp help ; not a number
is_a_number:
; check for last digit by looking at next character
cmp byte ptr [bx+1],CR
je last_digit
cmp byte ptr [bx+1],SPACE
je last_digit
cmp byte ptr [bx+1],TAB
jne store_digit
last_digit:
inc cl ; increment parameter count
store_digit:
mov al,byte ptr [bx]
sub al,'0' ; convert ASCII to BCD
mov byte ptr [di],al ; store BCD digit in BCD_size
inc di ; increment storage pointer
inc dl ; increment digit count
cmp dl,5 ; check digit count
jl jump_to_parse ; less than 5 digits
jmp help ; too many digits in disk size
jump_to_parse:
jmp parse_loop ; continue parsing parameters
check_option:
cmp cl,8
jl parse_option ; less than 8 parameters ?
jmp help ; too many parameters
parse_option:
and byte ptr [bx],5fh
cmp byte ptr [bx],'V' ; check for verify option
je set_verify
cmp byte ptr [bx],'S' ; check for system option
je set_system
cmp byte ptr [bx],'N' ; check for skip prompt option
je clear_prompt
cmp byte ptr [bx],'R' ; check for recursion option
je set_recursion
cmp byte ptr [bx],'D' ; check for standard option
je set_standard
cmp byte ptr [bx],'U' ; check for UNIX option
je set_unix
cmp byte ptr [bx],'C' ; check for 720K option
je set_cluster
jmp help ; invalid option
set_verify:
mov byte ptr [verify],1 ; set format verify true
inc cl
jmp parse_loop
set_standard:
mov byte ptr [standard],1 ; set standard parameters true
inc cl
jmp parse_loop
set_unix:
mov byte ptr [unix],1 ; set UNIX format option true
inc cl
jmp parse_loop
set_cluster:
mov byte ptr [cluster_720K],1 ; set 720K option true
inc cl
jmp parse_loop
set_system:
mov byte ptr [system],1 ; set transfer system true
inc cl
jmp parse_loop
clear_prompt:
cmp byte ptr [prmt_or_rcrs],FALSE
je prompt_ok
exclusive:
; mutually exclusive options specified
mov dx,offset option_error
mov ah,09h
int 21h
; set exit code to 12 (mutually exclusive options)
mov sp,word ptr [stack_pointer]
mov ax,4c0ch
int 21h
prompt_ok:
mov byte ptr [prmt_or_rcrs],TRUE
mov byte ptr [recurse],FALSE
mov byte ptr [prompt],FALSE
inc cl
jmp parse_loop
set_recursion:
cmp byte ptr [prmt_or_rcrs],FALSE
je recurse_ok
jmp exclusive
recurse_ok:
mov byte ptr [prmt_or_rcrs],TRUE
mov byte ptr [recurse],TRUE
mov byte ptr [prompt],TRUE
inc cl
jmp parse_loop
got_command:
cmp cl,2
jnl two_parameters
jmp help ; too few parameters
two_parameters:
cmp dl,3
jge three_digits
jmp help ; too few digits in disk size
three_digits:
; convert the disk size parameter from BCD to binary
mov cl,dl
dec di
xor ah,ah
mov al,byte ptr [di]
mov word ptr [binary_size],ax
dec di
dec cl
xor ah,ah
mov al,byte ptr [di]
imul ax,10
add word ptr [binary_size],ax
dec di
dec cl
xor ah,ah
mov al,byte ptr [di]
imul ax,100
add word ptr [binary_size],ax
dec di
dec cl
jz test_size_360
xor ah,ah
mov al,byte ptr [di]
imul ax,1000
add word ptr [binary_size],ax
test_size_360:
cmp word ptr [binary_size],360
jne test_size_1200 ; not 360 Kb
mov byte ptr [disk_size],1
jmp short set_up ; command line is valid
test_size_1200:
cmp word ptr [binary_size],1200
jne test_size_720 ; not 1.2 Mb
mov byte ptr [disk_size],2
jmp short set_up ; command line is valid
test_size_720:
cmp word ptr [binary_size],720
jne test_size_1440 ; not 720 Kb
mov byte ptr [disk_size],3
jmp short set_up ; command line is valid
test_size_1440:
cmp word ptr [binary_size],1440
jne test_size_2880 ; not 1.44 Mb
mov byte ptr [disk_size],4
jmp short set_up ; command line is valid
test_size_2880:
cmp word ptr [binary_size],2880
jne help ; not 2.88 Mb
mov byte ptr [disk_size],5
jmp short set_up ; command line is valid
help:
; command line is invalid or null
mov dx,offset help_message
mov ah,09h
int 21h
; set exit code to 4 (null or invalid command line)
mov sp,word ptr [stack_pointer]
mov ax,4c04h
int 21h
;***********************************************************************
; set up the drive parameters and the parameter table
;***********************************************************************
set_up:
; check for 720K option
cmp byte ptr [cluster_720K],FALSE
je no_720K_error
cmp word ptr [binary_size],720
je no_720K_error
mov dx,offset cluster_720K_error
mov ah,09h
int 21h
; set exit code to 13 (720K option on wrong disk size)
mov sp,word ptr [stack_pointer]
mov ax,4c0Dh
int 21h
no_720K_error:
; if transfering system, check file copy buffer space
cmp byte ptr [system],1
jne cursor_off
; calculate copy buffer size
mov ax,sp
cmp ax,offset file_buffer
jb no_buffer
sub ax,offset file_buffer
sbb ax,word ptr [stack_size]
jc no_buffer
cmp ax,word ptr [minimum_buffer]
jnb buffer_ok
no_buffer:
mov dx,offset buffer_space_error
mov ah,09h
int 21h
; set exit code to 7 (no room for file copy buffer)
mov sp,word ptr [stack_pointer]
mov ax,4c07h
int 21h
buffer_ok:
mov word ptr [buffer_size],ax
cursor_off:
; save the current cursor and then turn the cursor off
mov ah,03h
int 10h
mov word ptr [cursor],cx
or cx,2000h
mov ah,01h
int 10h
; issue a carrriage-return / line-feed to stdout
mov dx,offset cr_lf
mov ah,09h
int 21h
; save the original disk parameter table pointer
xor ax,ax
mov es,ax
assume es:seg_zero
mov ax,word ptr es:[0078h]
mov dx,word ptr es:[007ah]
mov word ptr [parameter_pointer],ax
mov word ptr [parameter_pointer+2],dx
; save the original control-break vector
mov ax,word ptr es:[008ch]
mov dx,word ptr es:[008eh]
mov word ptr [control_break],ax
mov word ptr [control_break+2],dx
recursion_loop:
xor ax,ax
mov es,ax
assume es:seg_zero
; set the disk parameter table pointer for formatting
xor ah,ah
mov al,byte ptr [disk_size]
dec ax
imul ax,11
cmp byte ptr [standard],1
je use_standard
add ax,offset parameter_table
jmp short use_fast
use_standard:
add ax,offset standard_parameter_table
use_fast:
mov bx,offset break_handler
cli
mov word ptr es:[0078h],ax
mov word ptr es:[007ah],cs
; set the new control-break vector
mov word ptr es:[008ch],bx
mov word ptr es:[008eh],cs
sti
push cs
pop es
assume es:cseg
; check for prompt bypass
cmp byte ptr [prompt],1
jne no_prompt
; clear the message line
mov dx,offset clear_line
mov ah,09h
int 21h
eat_keystroke:
; eat any pending keystrokes
mov ah,01h
int 16h
jz no_keystroke
xor ah,ah
int 16h
jmp eat_keystroke
no_keystroke:
; prompt for a floppy
mov dx,offset insert_floppy
mov ah,09h
mov al,byte ptr [drive_number]
add al,41h
mov byte ptr [insert_drive],al
int 21h
; wait for a key press
xor ah,ah
int 16h
cmp ax,CTRL_C_KEY ; control-C
jne escape
jmp break_handler
escape:
cmp ax,ESC_KEY ; escape
jne clear
jmp break_handler
clear:
; clear the message line
mov dx,offset clear_line
mov ah,09h
int 21h
no_prompt:
mov dx,offset initializing
mov ah,09h
int 21h
; get disk drive information
; note: Some machines do not support this function call,
; this makes it difficult to determine if the
; requested drive and the requested disk size are
; compatible prior to attempting the format. What
; this BIOS function should do is read the floppy
; type from the CMOS RAM, then set the registers
; as appropriate for that type.
push es
mov ah,08h
mov dl,byte ptr [drive_number]
int 13h
jnc got_drive_type
; keep going if the bios does not support this function
cmp ah,01h
jne no_drive_type
; get the drive type the hard way (from the CMOS RAM)
mov al,10h
out 70h,al
; note: Very fast machines may need additional I/O wait
; time here. This is common on 80486 machines.
jmp short $+2
jmp short $+2
in al,71h
cmp dl,0
jne drive_b
and al,0f0h
shr al,4
drive_b:
and al,0fh
mov bl,al
cmp bl,1
jne not_360
mov cx,2709h
jmp short got_drive_type
not_360:
cmp bl,2
jne not_1200
mov cx,4f0fh
jmp short got_drive_type
not_1200:
cmp bl,3
jne not_720
mov cx,4f09h
jmp short got_drive_type
not_720:
cmp bl,4
jne not_1440
mov cx,4f12h
jmp short got_drive_type
not_1440:
cmp bl,5
jne not_2880
mov cx,4f24h
jmp short got_drive_type
not_2880:
cmp bl,0
je got_drive_type
no_drive_type:
mov dx,offset clear_line
mov ah,09h
int 21h
mov dx,offset get_type_error
mov ah,09h
int 21h
; set exit code to 10 (unknown drive type)
mov ax,4c0ah
push ax
jmp error_exit
got_drive_type:
cmp bl,0
jne drive_exists
mov dx,offset clear_line
mov ah,09h
int 21h
mov dx,offset no_drive_error
mov ah,09h
int 21h
; set exit code to 3 (drive does not exist)
mov ax,4c03h
push ax
jmp error_exit
drive_exists:
cmp bl,5
; drive type greater than 2.88 Mb ?
jg no_drive_type
mov byte ptr [max_track],ch
mov byte ptr [sectors_track],cl
mov byte ptr [drive_type],bl
mov ah,byte ptr [disk_size]
mov al,bl
mov word ptr [disk_drive],ax
; check for floppy size less than drive maximum capacity
; check for a 360 Kb floppy in a 1.2 Mb drive
cmp word ptr [disk_drive],0102h
je forty_tracks
; check for a 720 Kb floppy in a 1.2 Mb drive
cmp word ptr [disk_drive],0302h
je nine_sectors
; check for a 720 Kb floppy in a 1.44 Mb drive
cmp word ptr [disk_drive],0304h
je nine_sectors
; check for a 720 Kb floppy in a 2.88 Mb drive
cmp word ptr [disk_drive],0305h
je nine_sectors
; check for a 1.44 Mb floppy in a 2.88 Mb drive
cmp word ptr [disk_drive],0405h
je eighteen_sectors
jmp short check_for_bad
forty_tracks:
mov byte ptr [max_track],39
nine_sectors:
mov byte ptr [sectors_track],9
jmp size_ok
eighteen_sectors:
mov byte ptr [sectors_track],18
jmp size_ok
check_for_bad:
; check for improper disk / drive cominations
cmp word ptr [disk_drive],0201h
je bad_size ; 1.2 Mb in 360 Kb
cmp word ptr [disk_drive],0301h
je bad_size ; 720 Kb in 360 Kb
cmp word ptr [disk_drive],0401h
je bad_size ; 1.44 Mb in 360 Kb
cmp word ptr [disk_drive],0302h
je bad_size ; 720 Kb in 1.2 Mb
cmp word ptr [disk_drive],0402h
je bad_size ; 1.44 Mb in 1.2 Mb
cmp word ptr [disk_drive],0103h
je bad_size ; 360 Kb in 720 Kb
cmp word ptr [disk_drive],0203h
je bad_size ; 1.2 Mb in 720 Kb
cmp word ptr [disk_drive],0403h
je bad_size ; 1.44 Mb in 720 Kb
cmp word ptr [disk_drive],0104h
je bad_size ; 360 Kb in 1.44 Mb
cmp word ptr [disk_drive],0204h
je bad_size ; 1.2 Mb in 1.44 Mb
cmp word ptr [disk_drive],0501h
je bad_size ; 2.88 Mb in 360 Kb
cmp word ptr [disk_drive],0502h
je bad_size ; 2.88 Mb in 1.2 Mb
cmp word ptr [disk_drive],0503h
je bad_size ; 2.88 Mb in 720 Kb
cmp word ptr [disk_drive],0504h
je bad_size ; 2.88 Mb in 1.44 Mb
cmp word ptr [disk_drive],0105h
je bad_size ; 360 Kb in 2.88 Mb
cmp word ptr [disk_drive],0205h
je bad_size ; 1.2 Mb in 2.88 Mb
jmp short size_ok
bad_size:
mov dx,offset clear_line
mov ah,09h
int 21h
mov dx,offset set_disk_error
mov ah,09h
int 21h
; set exit code to 2 (disk / drive comination error)
mov ax,4c02h
push ax
jmp error_exit
size_ok:
; put the parameter table in the boot record
pop es
xor ah,ah
mov al,byte ptr [disk_size]
dec ax
imul ax,11
add ax,offset parameter_table
mov si,ax
mov di,offset disk_table
mov cx,11
cld
rep movsb
;***********************************************************************
; store the disk parameters in the boot record and FAT
;***********************************************************************
push si
; calculate the offset to the parameters in floppy_table
xor ah,ah
mov al,byte ptr [disk_size]
dec ax
imul ax,10
mov bx,ax
mov si,offset floppy_table
cmp byte ptr [cluster_720K],TRUE
jne normal_720K
add si,30
normal_720K:
; set the media descriptor byte
mov al,byte ptr [si+bx]
mov byte ptr [descriptor],al
mov byte ptr [fat_record],al ; first byte of FAT
; set the number of root directory entries
mov ax,word ptr [si+bx+4]
mov word ptr [directory_size],ax
; set the number of sectors per directory
mov al,byte ptr [si+bx+6]
mov byte ptr [sectors_directory],al
; set the number of sectors per cluster
mov al,byte ptr [si+bx+7]
mov byte ptr [sectors_cluster],al
; set the number of sectors per FAT
mov ax,word ptr [si+bx+8]
mov word ptr [sectors_fat],ax
; set the total number of sectors per disk
xor dx,dx
xor ah,ah
mov al,byte ptr [max_track]
inc ax
mul word ptr [sectors_track]
xor bh,bh
mov bl,byte ptr [heads]
mul bx
mov word ptr [small_total],ax
; calculate the location of the first directory sector
xor dx,dx
xor ah,ah
mov al,byte ptr [fats]
mul word ptr [sectors_fat]
add ax,word ptr [hidden_sectors]
add ax,word ptr [reserved_sectors]
; store directory start sector (absolute sector number)
mov word ptr [dir_start],ax
; calculate the location of the first data sector
xor bh,bh
mov bl,byte ptr [sectors_directory]
add ax,bx
; store data start sector (absolute sector number)
mov word ptr [data_start],ax
pop si
; reset the disk controller
call reset
jnc set_drive
jmp write_error
;***********************************************************************
; set the drive type for format
;***********************************************************************
set_drive:
mov byte ptr [retry_count],3
drive_retry:
mov al,byte ptr [drive_type]
cmp al,3
jl five_inch
mov al,4
jmp short set_type
five_inch:
cmp al,2
jne low_density
cmp byte ptr [disk_size],1
jg high_density
mov al,2
jmp short set_type
high_density:
mov al,3
jmp short set_type
low_density:
mov al,1
set_type:
mov ah,17h
int 13h
jnc short set_disk
cmp ah,80h
jne floppy_exists
mov dx,offset no_floppy_error
jmp write_error
floppy_exists:
; keep going if the bios does not support this function
cmp ah,01h
je set_disk
; reset the disk controller
call reset
dec byte ptr [retry_count]
jnz drive_retry
mov dx,offset set_drive_error
jmp write_error
;***********************************************************************
; set the disk type for format
;***********************************************************************
set_disk:
mov byte ptr [retry_count],3
disk_retry:
push es
push di
mov ah,18h
mov ch,byte ptr [max_track]
mov cl,byte ptr [sectors_track]
mov dl,byte ptr [drive_number]
int 13h
pop di
pop es
jnc format_disk
; keep going if the bios does not support this function
cmp ah,01h
je format_disk
; reset the disk controller
call reset
dec byte ptr [retry_count]
jnz disk_retry
mov dx,offset set_disk_error
jmp write_error
;***********************************************************************
; format the disk
;***********************************************************************
format_disk:
; start at track zero
call track_zero
; set up the loop counter
xor ch,ch
mov cl,byte ptr [max_track]
inc cx
format_loop:
cmp byte ptr [prompt],TRUE
jne no_key_ready
; check for pending keystrokes
mov ah,01h
int 16h
jz no_key_ready
xor ah,ah
int 16h
cmp ax,CTRL_C_KEY ; control-C
jne not_Ctrl_C
jmp break_handler
not_Ctrl_C:
cmp ax,ESC_KEY ; escape
jne format_loop
jmp break_handler
no_key_ready:
push cx
call format_track
jnc continue
pop cx
jmp write_error
continue:
call next_track
pop cx
loop format_loop
;***********************************************************************
; set up the volume serial number in the boot record
;***********************************************************************
cmp byte ptr [unix],1
jne serial_number
jmp exit
serial_number:
; the disk serial number is a four byte number made up
; from the system clock as follows :
; byte 0 = day + hundredths of a second
; byte 1 = month + second
; byte 2 = low byte of year + minute
; byte 3 = high byte of year + hour
; this method of serial number generation makes the
; possibility of duplicate serial numbers occuring
; extremely low, but not impossible
; get the system time
mov ah,2ch
int 21h
push dx
push cx
; get the system date
mov ah,2ah
int 21h
pop ax
add cx,ax
pop ax
add dx,ax
; store the serial number in the boot record
mov word ptr [sn_low],cx
mov word ptr [sn_high],dx
;***********************************************************************
; set up the system file names in the boot record
;***********************************************************************
; get default drive
mov ah,19h
int 21h
; set source drive
add al,41h
mov byte ptr [ibm_bios_source_path],al
mov byte ptr [ms_bios_source_path],al
; attempt to open IO.SYS
mov dx,offset ms_bios_source_path
xor al,al
mov ah,3dh
int 21h
jnc found_ms
; attempt to open IBMBIO.COM
mov dx,offset ibm_bios_source_path
xor al,al
mov ah,3dh
int 21h
jnc found_ibm
; no system on default drive
mov byte ptr [system_exists],FALSE
jmp short write_boot
found_ms:
; close the file
mov bx,ax
mov ah,3eh
int 21h
mov byte ptr [system_exists],TRUE
mov byte ptr [is_ibm],FALSE
; fix the bios name in the boot record
mov cx,11
mov si,offset ms_bios_name
mov di,offset bios_name
cld
rep movsb
mov cx,11
mov si,offset ms_dos_name
mov di,offset dos_name
cld
rep movsb
jmp short write_boot
found_ibm:
; close the file
mov bx,ax
mov ah,3eh
int 21h
mov byte ptr [system_exists],TRUE
mov byte ptr [is_ibm],TRUE
; fix the bios name in the boot record
mov cx,11
mov si,offset ibm_bios_name
mov di,offset bios_name
cld
rep movsb
mov cx,11
mov si,offset ibm_dos_name
mov di,offset dos_name
cld
rep movsb
;***********************************************************************
; write the boot record and FAT1
;***********************************************************************
write_boot:
mov dx,offset boot_message
mov ah,09h
int 21h
mov byte ptr [retry_count],3
boot_retry:
mov ax,0302h
mov bx,offset DOS_boot
mov cx,0001h
xor dh,dh
mov dl,byte ptr [drive_number]
int 13h
jnc short finish_fat1
; reset the disk controller
call reset
dec byte ptr [retry_count]
jnz boot_retry
mov dx,offset write_boot_error
jmp write_error
finish_fat1:
mov dx,offset fat_message
mov ah,09h
int 21h
; set the starting sector (absolute)
mov ax,2
; set the number of sectors to write
mov cx,word ptr [sectors_fat]
dec cx
fat1:
push ax
push cx
push dx
call write_ths
mov bx,offset fat_dir_record
mov byte ptr [retry_count],3
fat1_retry:
call write_disk
jnc fat1_write_ok
; reset the disk controller
call reset
dec byte ptr [retry_count]
jnz fat1_retry
pop ax
pop ax
pop ax
mov dx,offset write_fat_error
jmp write_error
fat1_write_ok:
pop dx
pop cx
pop ax
; increment the absolute sector number
add ax,1
loop fat1
jnc write_fat
mov dx,offset write_fat_error
jmp write_error
;***********************************************************************
; write FAT2
;***********************************************************************
write_fat:
mov byte ptr [retry_count],3
fat_retry:
mov ax,0301h
mov bx,offset fat_record
xor ch,ch
mov cl,byte ptr [sectors_fat]
add cl,2
xor dh,dh
mov dl,byte ptr [drive_number]
int 13h
jnc finish_fat2
; reset the disk controller
call reset
dec byte ptr [retry_count]
jnz fat_retry
mov dx,offset write_fat_error
jmp write_error
finish_fat2:
; set the starting sector (absolute)
mov ax,2
add ax,word ptr [sectors_fat]
; set the number of sectors to write
mov cx,word ptr [sectors_fat]
dec cx
fat2:
push ax
push cx
push dx
call write_ths
mov bx,offset fat_dir_record
mov byte ptr [retry_count],3
fat2_retry:
call write_disk
jnc fat2_write_ok
; reset the disk controller
call reset
dec byte ptr [retry_count]
jnz fat2_retry
pop ax
pop ax
pop ax
mov dx,offset write_fat_error
jmp write_error
fat2_write_ok:
pop dx
pop cx
pop ax
; increment the absolute sector number
add ax,1
loop fat2
jnc write_dir
mov dx,offset write_fat_error
jmp write_error
;***********************************************************************
; write the root directory
;***********************************************************************
write_dir:
mov dx,offset dir_message
mov ah,09h
int 21h
; set the starting sector (absolute)
mov ax,word ptr [sectors_fat]
mul byte ptr [fats]
add ax,word ptr [reserved_sectors]
; set the number of sectors to write
xor ch,ch
mov cl,byte ptr [sectors_directory]
dir:
push ax
push cx
push dx
call write_ths
mov bx,offset fat_dir_record
mov byte ptr [retry_count],3
dir_retry:
call write_disk
jnc dir_write_ok
; reset the disk controller
call reset
dec byte ptr [retry_count]
jnz dir_retry
pop ax
pop ax
pop ax
mov dx,offset write_dir_error
jmp short write_error
dir_write_ok:
pop dx
pop cx
pop ax
; increment the absolute sector number
add ax,1
loop dir
jnc transfer
mov dx,offset write_dir_error
jmp short write_error
transfer:
cmp byte ptr [system],1
jne exit
cmp byte ptr [system_exists],TRUE
jne no_system
; transfer the system files
call load_system
pushf
; restore the original disk parameter table pointer
; this must be done because the create file function
; used in copying the system files will reset some of
; the values in the floppy parameter table to their
; default values. When recursive formatting is enabled,
; the parameter table will be reset before each floppy.
mov cx,word ptr [parameter_pointer]
mov dx,word ptr [parameter_pointer+2]
push es
xor ax,ax
mov es,ax
assume es:seg_zero
cli
mov word ptr es:[0078h],cx
mov word ptr es:[007ah],dx
sti
pop es
assume es:cseg
popf
jnc exit
no_system:
; set exit code to 5 (error copying system files)
mov ax,4c05h
push ax
jmp short error_exit
write_error:
push dx
mov dx,offset clear_line
mov ah,09h
int 21h
pop dx
mov ah,09h
int 21h
; set exit code to 1 (format, verify, or write error)
mov ax,4c01h
push ax
cmp byte ptr [recurse],FALSE
je error_exit
pop ax
jmp recursion_loop
;***********************************************************************
; clean up and exit or recurse
;***********************************************************************
exit:
cmp byte ptr [recurse],FALSE
je no_recursion
; display format complete message
mov dx,offset exit_message
mov ah,09h
int 21h
jmp recursion_loop
no_recursion:
; set exit code to 0 (Success)
mov ax,4c00h
push ax
error_exit:
; restore the original disk parameter table pointer
; and the original control-break handler
mov cx,word ptr [parameter_pointer]
mov dx,word ptr [parameter_pointer+2]
push es
xor ax,ax
mov es,ax
assume es:seg_zero
mov ax,word ptr [control_break]
mov bx,word ptr [control_break+2]
cli
mov word ptr es:[008ch],ax
mov word ptr es:[008eh],bx
mov word ptr es:[0078h],cx
mov word ptr es:[007ah],dx
sti
pop es
assume es:cseg
; reset the disk controller
call reset
pop ax
push ax
cmp al,0
jne abnormal_exit
; display format complete message
mov dx,offset exit_message
mov ah,09h
int 21h
abnormal_exit:
; restore the cursor
mov cx,word ptr [cursor]
mov ah,01h
int 10h
; terminate with exit code (0 = Success, else = Failure)
pop ax
mov sp,word ptr [stack_pointer]
int 21h
;***********************************************************************
; format subroutines
;***********************************************************************
;***********************************************************************
; reset the disk controller
;***********************************************************************
reset:
mov byte ptr [reset_retry_count],3
reset_retry:
xor ah,ah
mov dl,byte ptr [drive_number]
int 13h
jnc short reset_exit
dec byte ptr [reset_retry_count]
jnz reset_retry
mov dx,offset reset_error
stc
reset_exit: ret
;***********************************************************************
; control-break handler
;***********************************************************************
break_handler:
; restore the stack pointer
mov sp,word ptr [stack_pointer]
cmp ax,CTRL_C_KEY ; control-C
je control_c
cmp ax,ESC_KEY ; escape
je control_c
; undo the CR-LF generated by the break
mov bh,0
mov ah,03h
int 10h
dec dh
mov dl,50
mov ah,02
int 10h
control_c:
mov dx,offset clear_line
mov ah,09h
int 21h
mov dx,offset user_abort
mov ah,09h
int 21h
mov ax,4c09h
push ax
jmp error_exit
;***********************************************************************
; information display during format
;
; input:
;
; al = track number
; bl = head number
;***********************************************************************
display_format:
xor ah,ah
aam
or ax,3030h
mov byte ptr [format_track_number+1],al
cmp ah,30h
jne format_digit
mov ah,20h
format_digit:
mov byte ptr [format_track_number],ah
mov al,bl
xor ah,ah
aam
or ax,3030h
mov byte ptr [format_head_number],al
mov dx,offset format_display
mov ah,09h
int 21h
ret
;***********************************************************************
; information display during verification
;
; input:
;
; al = track number
; bl = head number
;***********************************************************************
display_verify:
xor ah,ah
aam
or ax,3030h
mov byte ptr [verify_track_number+1],al
cmp ah,30h
jne verify_digit
mov ah,20h
verify_digit:
mov byte ptr [verify_track_number],ah
mov al,bl
xor ah,ah
aam
or ax,3030h
mov byte ptr [verify_head_number],al
mov dx,offset verify_display
mov ah,09h
int 21h
ret
;***********************************************************************
; set the track number in the sector tables to zero
;***********************************************************************
track_zero:
xor ch,ch
mov cl,72
mov bx,offset sector_table_0
zero_counter:
mov byte ptr [bx],0
add bx,4
loop zero_counter
ret
;***********************************************************************
; increment the track number in the sector tables
;***********************************************************************
next_track:
xor ch,ch
mov cl,72
mov bx,offset sector_table_0
track_counter:
inc byte ptr [bx]
add bx,4
loop track_counter
ret
;***********************************************************************
; format (and possibly verify) both heads on one track
;***********************************************************************
format_track:
mov al,byte ptr [sector_table_0]
mov bl,0
; display formatting message
call display_format
mov byte ptr [retry_count],3
head_0_retry:
mov ah,5
mov al,byte ptr [sectors_track]
mov bx,offset sector_table_0
mov ch,byte ptr [bx]
mov cl,byte ptr [bx+2]
mov dh,byte ptr [bx+1]
mov dl,byte ptr [drive_number]
push ax
int 13h
pop bx
pushf
and al,0
or al,bl
popf
jnc short head_0_ok
cmp ah,80h
jne no_timeout
mov dx,offset no_floppy_error
stc
ret
no_timeout:
cmp ah,03h
jne not_protected
mov dx,offset write_protect_error
stc
ret
not_protected:
; reset the disk controller
call reset
dec byte ptr [retry_count]
jnz head_0_retry
mov dx,offset error_during_format
stc
ret
head_0_ok:
cmp byte ptr [verify],1
je verify_head_0
; check for proper floppy type
;
; this is done via a verification of track 79, for head
; 0 only, for all 1.2 Mb disks not being verified, and
; on track 0 head 0 only, for 360 Kb, 720 Kb, 1.44 Mb,
; and 2.88 Mb disks not being verified.
;
; the following combinations will fail at track 0:
;
; 1: trying to format a 1.2 Mb floppy to 360 Kb
; 2: trying to format a 720 Kb floppy to 1.44 Mb *
; 3: trying to format a 1.44 Mb floppy to 720 Kb * !
; 4: trying to format a 720 Kb floppy to 2.88 Mb *
; 5: trying to format a 2.88 Mb floppy to 720 Kb * !
; 6: trying to format a 2.88 Mb floppy to 1.44 Mb * !
;
; the following combination will fail at track 79:
;
; 1: trying to format a 360 Kb floppy to 1.2 Mb (it will
; probably fail sooner, but it is sure to fail here)
;
; notes:
;
; * - these combinations may not fail if the drive-
; controller combination does not properly detect
; the the floppy type.
;
; ! - this combination may not fail in 720 Kb drives.
;
; While certain non-standard combinations may not fail,
; either the data on the disk may be at risk, or your
; pocketbook may suffer, if you insist on using them.
cmp byte ptr [disk_size],2
je one_point_two
cmp byte ptr [sector_table_0],0
je verify_type
jmp short format_head_1
one_point_two:
cmp byte ptr [sector_table_0],79
je verify_type
jmp short format_head_1
verify_type:
mov ah,04h
int 13h
jnc format_head_1
mov dx,offset disk_type_error
stc
ret
verify_head_0:
pushf
pusha
mov al,byte ptr [sector_table_0]
mov bl,0
; display verifying message
call display_verify
popa
popf
mov ah,04h
int 13h
jnc format_head_1
mov dx,offset verify_error
stc
ret
format_head_1:
pushf
pusha
mov al,byte ptr [sector_table_0]
mov bl,1
; display formatting message
call display_format
popa
popf
mov byte ptr [retry_count],3
head_1_retry:
mov ah,5
mov al,byte ptr [sectors_track]
mov bx,offset sector_table_1
mov ch,byte ptr [bx]
mov cl,byte ptr [bx+2]
mov dh,byte ptr [bx+1]
mov dl,byte ptr [drive_number]
push ax
int 13h
pop bx
pushf
and al,0
or al,bl
popf
jnc short head_1_ok
; reset the disk controller
call reset
dec byte ptr [retry_count]
jnz head_1_retry
mov dx,offset error_during_format
stc
ret
head_1_ok:
cmp byte ptr [verify],1
je verify_head_1
format_return:
clc
ret
verify_head_1:
pushf
pusha
mov al,byte ptr [sector_table_1]
mov bl,1
; display verifying message
call display_verify
popa
popf
mov ah,04h
int 13h
jnc format_return
mov dx,offset verify_error
stc
ret
;***********************************************************************
; calculate the track, head, and sector for a disk write
;***********************************************************************
write_ths:
; calculate the sector number
xor dx,dx
div word ptr [sectors_track]
inc dl
; store the sector number
mov byte ptr [write_sector],dl
; calculate the head number and the track number
xor dx,dx
div word ptr [heads]
; store the head number
mov byte ptr [write_head],dl
; store the track number
mov word ptr [write_track],ax
ret
;***********************************************************************
; write one sector to the disk
;***********************************************************************
write_disk:
; get the track number
mov dx,word ptr [write_track]
; shift the upper 2 bits of the track number
; into the upper 2 bits of the sector number
shl dh,6
; get the sector number
or dh,byte ptr [write_sector]
mov cx,dx
xchg ch,cl
; get the drive number
mov dl,byte ptr [drive_number]
; get the head number
mov dh,byte ptr [write_head]
; write one sector to the disk
mov ax,0301h
int 13h
ret
;***********************************************************************
; transfer the system files
;***********************************************************************
load_system:
mov dx,offset file_copy_message
mov ah,09h
int 21h
; get default drive
mov ah,19h
int 21h
; set source drive
add al,41h
mov byte ptr [ibm_bios_source_path],al
mov byte ptr [ibm_dos_source_path],al
mov byte ptr [ms_bios_source_path],al
mov byte ptr [ms_dos_source_path],al
mov byte ptr [cmd_source_path],al
; set destination drive
mov al,byte ptr [drive_number]
add al,41h
mov byte ptr [ibm_bios_destination_path],al
mov byte ptr [ibm_dos_destination_path],al
mov byte ptr [ms_bios_destination_path],al
mov byte ptr [ms_dos_destination_path],al
mov byte ptr [cmd_destination_path],al
; copy the bios system file (IBMBIO.COM or IO.SYS)
cmp byte ptr [is_ibm],TRUE
jne ms_bios
mov bx,offset file_buffer
mov cx,word ptr [buffer_size]
mov si,offset ibm_bios_source_path
mov di,offset ibm_bios_destination_path
call file_copy
jnc copy_dos
jmp short load_error
ms_bios:
mov bx,offset file_buffer
mov cx,word ptr [buffer_size]
mov si,offset ms_bios_source_path
mov di,offset ms_bios_destination_path
call file_copy
jc load_error
copy_dos:
; copy the dos system file (IBMDOS.COM or MSDOS.SYS)
cmp byte ptr [is_ibm],TRUE
jne ms_dos
mov bx,offset file_buffer
mov cx,word ptr [buffer_size]
mov si,offset ibm_dos_source_path
mov di,offset ibm_dos_destination_path
call file_copy
jnc copy_cmd
jmp short load_error
ms_dos:
mov bx,offset file_buffer
mov cx,word ptr [buffer_size]
mov si,offset ms_dos_source_path
mov di,offset ms_dos_destination_path
call file_copy
jc load_error
copy_cmd:
; copy COMMAND.COM
mov bx,offset file_buffer
mov cx,word ptr [buffer_size]
mov si,offset cmd_source_path
mov di,offset cmd_destination_path
call file_copy
load_error:
ret
;***********************************************************************
; copy a file
;
; input :
;
; bx = pointer to copy buffer
; cx = copy buffer size in bytes
; si = pointer to source path\filename
; di = pointer to destination path\filename
;***********************************************************************
; file copy variables
;***********************************************************************
source: dw ?
destination: dw ?
read_handle: dw ?
write_handle: dw ?
file_time: dw ?
file_date dw ?
file_attr: dw ?
bytes_read: dw ?
copy_buffer_size: dw ?
copy_buffer: dw ?
;***********************************************************************
; file copy error messages
;***********************************************************************
file_not_found:
db " - error opening input file"
db CR,LF
db "$"
file_create_error:
db " - error creating output file"
db CR,LF
db "$"
file_read_error:
db " - error reading file"
db CR,LF
db "$"
file_write_error:
db " - error writing file"
db CR,LF
db "$"
;***********************************************************************
file_copy:
mov word ptr [copy_buffer],bx
mov word ptr [copy_buffer_size],cx
mov word ptr [source],si
mov word ptr [destination],di
mov dx,word ptr [source]
mov ah,3dh
xor al,al
int 21h ; open source file
mov word ptr [read_handle],ax
jnc file_open
; display file not found message
mov dx,offset cr_lf
call write_message
mov dx,word ptr [source]
call write_message
mov dx,offset file_not_found
call write_message
jmp load_error
file_open:
mov ax,5700h
mov bx,word ptr [read_handle]
int 21h ; get file time and date
mov word ptr [file_time],cx
mov word ptr [file_date],dx
mov ax,4300h
mov dx,word ptr [source]
int 21h ; get file attributes
mov word ptr [file_attr],cx
mov al,byte ptr [drive_number]
mov cx,0000h
mov dx,word ptr [destination]
mov ah,3ch
int 21h ; create destination
mov word ptr [write_handle],ax
jnc copy_loop
; display file not created message
mov dx,offset cr_lf
call write_message
mov dx,word ptr [destination]
call write_message
mov dx,offset file_create_error
call write_message
jmp short copy_error
copy_loop:
call read_file
jnc file_read_ok
; display file read error message
mov dx,offset cr_lf
call write_message
mov dx,word ptr [source]
call write_message
mov dx,offset file_read_error
call write_message
jmp short copy_error
file_read_ok:
call write_file
jnc file_write_ok
; display file write error message
mov dx,offset cr_lf
call write_message
mov dx,word ptr [destination]
call write_message
mov dx,offset file_write_error
call write_message
jmp short copy_error
file_write_ok:
cmp ax,word ptr [copy_buffer_size]
je copy_loop
mov bx,word ptr [read_handle]
mov ah,3eh
int 21h ; close read_file
mov ax,5701h
mov bx,word ptr [write_handle]
mov cx,word ptr [file_time]
mov dx,word ptr [file_date]
int 21h ; set file time and date
mov bx,word ptr [write_handle]
mov ah,3eh
int 21h ; close write_file
mov ax,4301h
mov cx,word ptr [file_attr]
mov dx,word ptr [destination]
int 21h ; set file attributes
clc
ret
copy_error:
stc
ret
;***********************************************************************
; issue a file copy error message
;***********************************************************************
write_message:
mov ah,09h
int 21h
ret
;***********************************************************************
; read file block into buffer
;***********************************************************************
read_file:
mov cx,word ptr [copy_buffer_size]
mov bx,word ptr [read_handle]
mov dx,word ptr [copy_buffer]
mov ah,3fh
int 21h
mov word ptr [bytes_read],ax
ret
;***********************************************************************
; write file block from buffer
;***********************************************************************
write_file:
mov cx,word ptr [bytes_read]
mov bx,word ptr [write_handle]
mov dx,word ptr [copy_buffer]
mov ah,40h
int 21h
ret
;***********************************************************************
; boot sector data (track 0, head 0, sector 1)
;***********************************************************************
DOS_boot:
;***********************************************************************
cseg ends
.8086 ; enable the 8086 instruction set
cseg segment
;***********************************************************************
jmp boot_strap ; skip over data areas
;***********************************************************************
; DOS disk data area
;***********************************************************************
oem_name: db "MSDOS5.0" ; identify as an MSDOS 5.0 disk
bytes_sector: dw 512 ; bytes per sector
sectors_cluster: db ? ; filled in before writing boot
reserved_sectors: dw 1 ; number of reserved sectors
fats: db 2 ; number of FATs
directory_size: dw ? ; filled in before writing boot
small_total: dw ? ; filled in before writing boot
descriptor: db ? ; filled in before writing boot
sectors_fat: dw ? ; filled in before writing boot
sectors_track: dw ? ; filled in before writing boot
heads: dw 2 ; number of heads
hidden_sectors: dd 0 ; number of hidden sectors
big_total: dd 0 ; used for large partitions
physical_drive: db 0 ; part of why only A is bootable
reserved: db 0 ; not currently used by DOS
extended_boot: db 029h ; signature for DOS 4.0+ format
sn_low: dw ? ; filled in before writing boot
sn_high: dw ? ; filled in before writing boot
volume_label: db "NO NAME "
fat_type: db "FAT12 "
;***********************************************************************
; bootstrap program data area
;***********************************************************************
sectors_directory: db ? ; filled in before writing boot
dir_start: dw ? ; filled in before writing boot
data_start: dw ? ; filled in before writing boot
disk_table: db 11 dup (?) ; filled in before writing boot
bios_name: db 11 dup (?) ; filled in before writing boot
dos_name: db 11 dup (?) ; filled in before writing boot
track: dw ? ; bootstrap program variable
head: db ? ; bootstrap program variable
sector: db ? ; bootstrap program variable
;***********************************************************************
; bootstrap program error messages
;***********************************************************************
reset_message:
db CR,LF,LF
db "Disk controller error,"
db NULL
read_message:
db CR,LF,LF
db "Disk read error,"
db NULL
system_message:
db CR,LF,LF
db "No system on disk,"
db NULL
retry_message:
db CR,LF
db "Press any key to reboot."
db NULL
;***********************************************************************
; bootstrap program code
;***********************************************************************
boot_strap:
; disable interrupts while modifying segment registers
cli
; set the stack segment and the extra segment to 0000
xor ax,ax
mov es,ax
mov ss,ax
assume es:seg_zero,ss:seg_zero
; DOS loads the boot record at 0000:7c00,
; so put the stack just below it
mov sp,BOOT
; set up the parameters used by the BIOS program loader
push cs
pop ds
mov si,offset disk_table
mov bx,0078h
; push the BIOS program loader variables onto the stack
push ds ; ds:si points to the disk parameter table
push si
push ss ; ss:bx points to interrupt vector 0eh
push bx
; set the data segment to 0000
mov ds,ax
assume ds:seg_zero
; use the disk parameter table in the floppy boot record
mov word ptr [bx],BOOT+offset disk_table-offset DOS_boot
mov word ptr [bx+02],ax
; enable interrupts
sti
; reset the disk controller
int 13h
jnc reset_ok
; display reset error message
mov si,BOOT+offset reset_message-offset DOS_boot
call write_string
jmp short not_bootable
reset_ok:
; check for system name in boot record
cmp byte ptr ds:[BOOT+bios_name-DOS_boot],0
je system_error
; get directory start sector (absolute sector number)
mov ax,word ptr ds:[BOOT+dir_start-DOS_boot]
; get track, head, and sector
call calculate_ths
; set the offset of the disk read buffer
mov bx,0500h
; read the first directory sector
call read_disk
jc read_error
; check directory for the BIOS file
; (it must be the first directory entry)
mov di,bx
mov cx,11
mov si,BOOT+offset bios_name-offset DOS_boot
rep cmpsb
jnz system_error
; check directory for the DOS file
; (it must be the second directory entry)
lea di,[bx+32]
mov si,BOOT+offset dos_name-offset DOS_boot
mov cx,11
rep cmpsb
jnz system_error
;***********************************************************************
system_found:
; valid directory, attempt to boot from the disk
; get the data start sector (absolute sector number)
mov ax,word ptr ds:[BOOT+data_start-DOS_boot]
; set the offset of the disk read buffer
mov bx,0700h
; read 3 sectors (the length of the BIOS program loader)
mov cx,3
read_next:
push ax
push cx
push dx
; get track, head, and sector
call calculate_ths
; read one disk sector
call read_disk
pop dx
pop cx
pop ax
jc read_error
disk_read_ok:
; increment the sector to read
inc ax
; bump the offset of the read buffer by the sector size
add bx,word ptr ds:[BOOT+bytes_sector-DOS_boot]
loop read_next
; set up the parameters for the BIOS program loader
; get the media descriptor
mov ch,byte ptr ds:[BOOT+descriptor-DOS_boot]
; get the drive number
mov dl,byte ptr ds:[BOOT+physical_drive-DOS_boot]
; get the data start sector (absolute sector number)
xor ax,ax
mov bx,word ptr ds:[BOOT+data_start-DOS_boot]
; execute the BIOS program loader
jmp far ptr program_loader
;***********************************************************************
not_bootable:
; display retry message
mov si,BOOT+offset retry_message-offset DOS_boot
call write_string
; wait for a key to be pressed
xor ah,ah
int 16h
; clean up the stack
pop si
pop ds
pop [si]
pop [si+2]
; try to boot the system again
int 19h
;***********************************************************************
system_error:
; display the no system error message
mov si,BOOT+offset system_message-offset DOS_boot
call write_string
jmp not_bootable
;***********************************************************************
read_error:
; display the disk read error message
mov si,BOOT+offset read_message-offset DOS_boot
call write_string
jmp not_bootable
;***********************************************************************
; bootstrap subroutines
;***********************************************************************
;***********************************************************************
; write a message to the screen
;***********************************************************************
write_string:
; get one character
lodsb
; check for end of ASCIIZ string
or al,al
jnz next_char
ret
next_char:
; write one character to the screen
mov ah,0eh
; use video page 0, normal white text
mov bx,0007h
int 10h
jmp write_string
;***********************************************************************
; read a sector from the disk
;***********************************************************************
read_disk:
; get the track number
mov dx,word ptr ds:[BOOT+track-DOS_boot]
; shift the upper 2 bits of the track number
; into the upper 2 bits of the sector number
mov cl,06
shl dh,cl
; get the sector number
or dh,byte ptr ds:[BOOT+sector-DOS_boot]
mov cx,dx
xchg ch,cl
; get the drive number
mov dl,byte ptr ds:[BOOT+physical_drive-DOS_boot]
; get the head number
mov dh,byte ptr ds:[BOOT+head-DOS_boot]
; read one sector from the disk
mov ax,0201h
int 13h
ret
;***********************************************************************
; calculate the track, head, and sector numbers
;***********************************************************************
calculate_ths:
; calculate the sector number
xor dx,dx
div word ptr ds:[BOOT+sectors_track-DOS_boot]
inc dl
; store the sector number
mov byte ptr ds:[BOOT+sector-DOS_boot],dl
; calculate the head number and the track number
xor dx,dx
div word ptr ds:[BOOT+heads-DOS_boot]
; store the head number
mov byte ptr ds:[BOOT+head-DOS_boot],dl
; store the track number
mov word ptr ds:[BOOT+track-DOS_boot],ax
ret
;***********************************************************************
; put program information in boot record (and FMT.COM)
;***********************************************************************
program: db "FMT version 2.00 07-FEB-1993",NULL
author: db "Written by Clair Alan Hardesty",NULL
;***********************************************************************
; adjust the boot record size to 512 bytes
;***********************************************************************
fill: db (512-(offset fill-offset DOS_boot)-2) dup (0)
; note: if the boot record is too long, the assembler
; will issue an error message stating that a
; positive count is required for the dup command.
;***********************************************************************
; boot sector signature
;***********************************************************************
signature: dw 0AA55h
;***********************************************************************
; end of boot sector data
;***********************************************************************
;***********************************************************************
; FAT and directory data
;***********************************************************************
; the first FAT sector begins with the media descriptor
fat_record:
db ? ; filled in before writing FAT
db 0ffh,0ffh
; other FAT sectors and directory sectors are all zeros
fat_dir_record:
db 512 dup (0)
;***********************************************************************
; file copy buffer
;***********************************************************************
file_buffer:
; the system file copy buffer space starts here and
; extends to the bottom of the stack.
cseg ends
end entry_point
;***********************************************************************
; end of Fmt.asm
;***********************************************************************